<?php

class Func_Calculation_Calculation
{
    //时间字段
    public static $dateName = array(
        "loan_date", // "放款日期",
        "overdue_day", //"欠款起算日",
        "expiration_date", //宣告到期日",
        'target_date',// '欠款暂计日',
        'overdue_cycle_start',// '逾期当期起息日',
        'overdue_cycle_end',// '逾期当期结息日',
    );
    //金额字段
    public static $moneyName = array(
        "debt_principal",  // "欠款本金",
        "target_amount", //标的金额
        "loan_amount",   //借款金额
        "actual_amount", //实际放款金额
        "liquidated_damages", //违约金
        "service_fee",    // 服务费
        "total_arrears", //欠款总额
        'overdueInt',// '按天计算的逾期利息',
        'overdue_interest',// '逾期利息',
        "interest", //"利息",
        "repaid_principal", //"已收本金",
        "repaid_interest", //"已收利息",
        "repaid_fined_interest", //"已收罚息",
        "reduce_debt_principal", //"扣减后欠款本金",
    );
    //利率字段
    public static $rateName = array(
        "contract_rate", //约定利率,
        "liquidated_rate",  //违约金利率
        'overdue_rate',  //逾期利率
        "service_rate", // 服务费率
        "comprehensive_damages" // 综合利率
    );
    //其他字段
    public static $otherName = array(
        "loan_term",   // 借款期限(天),
        "overdue_days", //逾期天数
        "repaid_period", //已还期次
    );
    /**
     * 多个公式计算
     * @param array $formulaArr
     *          ex: [
     *              'dd' => （a+b)*c-e*f/g,
     *              'ff' => （a+b)*c-e*f/g,
     *               ]
     * @param array $dataArr
     *          ex: [
     *              'a' => 1,
     *              'b' => 1.292,
     *              'c'=>'2%',
     *              'c'=>'2.009',
     *              ]
     *
     * @return array
     *          ex: [
     *              'dd' => 303.22,
     *              'ff' => 200,
     *              ]
     */
    public static function calculationFormulaArr($formulaArr,$dataArr,$num = 1)
    {
        //异常数据判断  返回空数组,或者公式数组都为0
        if(empty($dataArr)){
            if(!empty($formulaArr)){
                foreach($formulaArr as $key => $val){
                    $formulaArr[$key] = 0;
                }
            }
            Func_Log::write("calculation", '参数为空', json_encode($formulaArr));
            return $formulaArr;
        }
        if(empty($formulaArr)){
            Func_Log::write("calculation", '公式为空', json_encode($formulaArr));
            return array();
        }

        //判断公式是否分段
        foreach ($formulaArr as $key => $formula){
            if( strpos($formula, '|')){
                //如果分段按照段数num取公式
                $formulaArr[$key] = explode("|",$formula)[$num-1];
            }
        }
        //判断公式数组里面需要计算字段是否要参与计算
        foreach($formulaArr as $key => $value){
            foreach ($formulaArr as $k => $v){
                if(strpos($v,$key)){
                    preg_match_all('/<.*?>/', $v, $parameterArr);
                    if(!empty($parameterArr[0])){
                        foreach($parameterArr[0] as $parameter){
                            $temp = trim(str_replace(array('<', '>'), array('', ''), $parameter));
                            if($temp == $key){
                                //替换
                                $formulaArr[$k] = str_replace($parameter,'('.$formulaArr[$key].')',$v);
                            }
                        }
                    }
                }
            }
        }
        $dataArr = self::buildData($dataArr);
        foreach($formulaArr as  $key => $formula){
            $formulaArr[$key] = self::calculation($formula,$dataArr,$num);
        }
        return $formulaArr;
    }
    /**
     * 单个公式计算
     * @param string $formula
     *             ex:  'dd' => （a+b)*c-e*f/g,
     * @param array $dataArr
     *          ex: [
     *              'a' => 1,
     *              'b' => 1.292,
     *              'c'=>'2%',
     *              'c'=>'2.009',
     *              ]
     *
     * @return float
     */
    public static function calculationFormula($formula,$dataArr,$num = 1)
    {
        if( strpos($formula, '|')){
            //如果分段按照段数num取公式
            $formula= explode("|",$formula)[$num-1];
        }
        //异常数据判断  返回0
        if(empty($dataArr)){
            Func_Log::write("calculation", '参数为空', $formula);
           return 0;
        }
        $dataArr = self::buildData($dataArr);
        return self::calculation($formula,$dataArr);
    }

    /**
     * 计算完成返回.
     * @param string $format
     * @param array $data
     *
     * @return float
     */
    public static function calculation($formula,$data){
        //公式里数据替换
        preg_match_all('/<.*?>/', $formula, $parameterArr);
        if (empty($parameterArr[0])) {
            return self::calculationReturn($formula);
        }
        foreach ($parameterArr[0] as $parameter) {
            $temp = trim(str_replace(array('<', '>'), array('', ''), $parameter));
            if(!isset($data[$temp])){
                Func_Log::write("calculation", '未找到参数', $temp);
                return 0;
            }
            $formula = str_replace($parameter, $data[$temp], $formula);
        }
        //公式里方法替换
        preg_match_all('/F.*?\(/', $formula, $functionArr);
        if(empty($functionArr[0])){
            return self::calculationReturn($formula);
        }
        foreach ($functionArr[0] as $function){
            $temp = rtrim($function,'(');
            $temp = ltrim($temp,'F');
            if (!method_exists('Func_Calculation_HelpFunction',$temp)){
                Func_Log::write("calculation", '未找到帮助方法', $temp);
                return 0;
            }
            $temp = 'Func_Calculation_HelpFunction::'.$temp.'(';
            $formula = str_replace($function, $temp, $formula);
        }
        return self::calculationReturn($formula);
    }
    /**
     * 计算完成返回.
     *
     * @param string $format
     *
     * @return string
     */
    public static function calculationReturn($formula)
    {
        $formula = str_replace('（', '(', $formula);
        $formula = str_replace('）', ')', $formula);

        //判断公式是否异常
        preg_match_all('/Func_Calculation_HelpFunction::.*?\(/', $formula, $functionArr);
        if (empty($functionArr[0])) {
            if (preg_match('/[a-zA-Z]/', $formula) || preg_match("/([\x81-\xfe][\x40-\xfe])/", $formula)) {
                Func_Log::write("calculation", '公式格式异常', $formula);
                return 0;
            }
            return self::formatFloat(eval("return $formula;"));
        }
        $tempformula = $formula;
        foreach ($functionArr[0] as $function) {
            $tempformula = str_replace(rtrim($function, '('), '', $tempformula);
        }
        if (preg_match('/[a-zA-Z<>]/', $tempformula) || preg_match("/([\x81-\xfe][\x40-\xfe])/", $tempformula)) {
            Func_Log::write("calculation", '公式格式异常', $formula);
            return 0;
        }
        Func_Log::write("calculation", 'success', $formula);
        return self::formatFloat(eval("return $formula;"));
    }
    /**
     * 统一处理浮点数.
     *
     * @param string $str
     *
     * @return string
     */
    public static function formatFloat( $str, $step = 100)
    {
         return is_numeric($str) ?  floor(strval($str * $step)) / $step : 0;
    }

    /**
     * 统一处数据.
     *
     * @param array $data
     *
     * @return $data
     */
    public static function buildData($data){
        $buildData = array();
        foreach ($data as $key => $val) {
            switch (true) {
                case in_array($key, self::$dateName) ://时间
                    $res = self::buildDate($val);
                    $buildData[$key] = $res ? $res : 0;
                    break;
                case in_array($key, self::$moneyName) ://金额
                    $res = self::buildMoney($val);
                    $buildData[$key] = $res ? $res : 0;
                    break;
                case in_array($key, self::$rateName) ://利率
                    $res = self::buildRate($val);
                    $buildData[$key] = $res ? $res : 0;
                    break;
                case in_array($key, self::$otherName) ://录入信息审核
                    $buildData[$key] = self::formatFloat($val);
                    break;
                default:
                    $buildData[$key] = 0;
                    break;
            }
        }
        return $buildData;
    }

    /**
     * 统一处理利率
     *
     * @param string $str
     *
     * @return string
     */
    public static function buildRate($rate){
        //是否有百分号
        if(strpos($rate, "%")){
            $rate = str_replace('%','',$rate);
            $rate = $rate/100;
        }
        return is_numeric($rate) ? $rate : 0;
    }

    /**
     * 统一处理时间
     *
     * @param string $str
     *
     * @return string
     */
    public static function buildDate($str){
        if(strlen($str) == 10 && is_numeric($str)){
            if(strtotime(date('Y-m-d H:i:s',$str)) === $str) {
                return $str;
            }
        }
        $str = str_replace(' ', '', $str);
        $str = rtrim($str,"秒");
        $nyr=array('年','月','日');
        $sf = array('时','分');
        foreach ($nyr as $val){
            if(strpos($str, $val)){
                $str = str_replace($val,"/",$str);
            }
        }
        foreach ($sf as $val){
            if(strpos($str, $val)){
                $str = str_replace($val,":",$str);
            }

        }
        return strtotime(rtrim($str,'/'));
    }

    /**
     * 统一处理金额
     *
     * @param string $money
     *
     * @return string
     */
    public static function buildMoney($money){
        //判断是否是逗号分隔
        $money = str_replace(' ', '', $money);
        $money = str_replace(',',"",$money);
        $money = str_replace('，',"",$money);
        //是否已经转换成功
        if(is_numeric($money)){
            return $money;
        }
        //判断是否是汉字金额
        $unit2Number=[
            '亿'=>100000000,
            '万'=>10000,
            '仟'=>1000,
            '千'=>1000,
            '佰'=>100,
            '百'=>100,
            '拾'=>10,
            '十'=>10,
            '圆'=>1,
            '块'=>1,
            '元'=>1,
            '角'=>0.1,
            '分'=>0.01,

        ];
        $cn2Number=[
            '零'=>0,
            '0'=>0,
            '壹'=>1,
            '一'=>1,
            '1'=>1,
            '贰'=>2,
            '两'=>2,
            '二'=>2,
            '2'=>2,
            '叁'=>3,
            '三'=>3,
            '3'=>3,
            '肆'=>4,
            '四'=>4,
            '4'=>4,
            '伍'=>5,
            '五'=>5,
            '5'=>5,
            '陆'=>6,
            '六'=>6,
            '6'=>6,
            '柒'=>7,
            '七'=>7,
            '7'=>7,
            '捌'=>8,
            '八'=>8,
            '8'=>8,
            '玖'=>9,
            '九'=>9,
            '9'=>9,
            '拾'=>10,
            '十'=>10,
            '10'=>10,

        ];

        $result = 0;

        foreach($unit2Number as $unit => $number){

            $pos = mb_strpos($money,$unit);

            if($pos === false){

//这个就是没有找到这个需要的单位

                continue;

            }

            $cn = mb_substr($money,0,$pos);

            if(mb_substr($cn,0,1) == '零'){

                $cn = mb_substr($cn,1);

            }

            $number = 0;

            if(mb_strlen($cn) == 1){

                $number = $cn2Number[$cn];

            }elseif(mb_strlen($cn)>1){

                $number = self::buildMoney($cn."圆");

            }
            $result += $number * $unit2Number[$unit];
            $money = mb_substr($money,$pos + mb_strlen($unit));

        }

        return $result;

    }

}
